﻿using Microsoft.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore.Storage.ValueConversion.Internal;
using Models.Common;
using Models.Device;
using Models.Task;
using Nancy.TinyIoc;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel.Design;
using System.Data;
using System.Linq;
using System.Reflection.Metadata;
using System.Text;
using System.Threading.Tasks;
using static Models.Common.EnumDeviceState;
using UtilsCache;
using UtilsBase;
using GatewayServerService.Data;
using Microsoft.EntityFrameworkCore.Metadata.Conventions;
using System.Diagnostics;
using UtilsORM;
using UtilsORM.MySqlData;
using Org.BouncyCastle.Asn1.X509.Qualified;

namespace GatewayServerService.CloudCenter
{

    /// <summary>
    /// 计划任务、流程步骤执行
    /// </summary>
    public class ServiceCloudTaskPlain
    {
        private static object obj_ServiceCloudTaskPlain = new object();
        public void taskRun()
        {
            try
            {
                new EFYihongIotContext().iot_device_task_plain_item_handle.ExecuteDelete();
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.ToString());
            }

            while (true)
            {
                try
                {
                    EFYihongIotContext ef = new EFYihongIotContext();
                    //EF查询不同分组的第一条数据,根据tpi_order排序,https://www.cnblogs.com/sangzs/p/15587162.html
                    List<iot_device_task_plain_item_handle> task_PlainList = ef.iot_device_task_plain_item_handle.GroupBy(c => new { c.tpi_tp_guid }).Select(d => d.OrderBy(c => c.tpi_order).FirstOrDefault()).ToList();
                    foreach (iot_device_task_plain_item_handle item in task_PlainList)
                    {
                        //判断是否延时，到时间没有
                        if (item.tpi_key == "delay" && item.tpi_execute_delayed_time != null)
                        {
                            if (item.tpi_execute_delayed_time > DateTime.Now)
                            {
                                continue;
                            }
                        }
                        handlePlainTask(item.tpi_tp_guid);
                    }
                    ef.Dispose();
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.ToString());
                }
                Thread.Sleep(500);
            }

        }
        /// <summary>
        /// 把要处理的流程任务写入到 待办表iot_device_task_plain_item_handle
        /// </summary>
        public void getTaskPlianTask(string tpguid = "")
        {
            try
            {
                //  if (UtilRedisNewLife.Lock("getTaskPlianTask" + tpguid))//避免上一次还没运行完，又到定时，运行一次相同的流程
                // {
                EFYihongIotContext ef = new EFYihongIotContext();

                iot_device_task_plain task_Plain = ef.iot_device_task_plain.Where(c => c.tp_guid == tpguid && c.tp_status == 0 && c.tp_auto_run == 0).FirstOrDefault();
                //new ServiceIotDeviceTaskPlainCache().getPlainCache(tpguid);
                if (task_Plain == null)
                {
                    return;
                }
                //判断是否上一次已经执行完毕
                if (task_Plain.tp_complete == 1)
                {
                    ef.iot_device_task_plain_item_handle.Where(c => c.tpi_tp_guid == task_Plain.tp_guid).ExecuteDelete();

                    //判断设备是否在线，不在线的话，就不执行了
                    List<iot_device_task_plain_item> plain_Items = new DBIotDeviceTaskPlainCache().getPlainItemCache(tpguid);// ef.iot_device_task_plain_item.Where(c => c.tpi_tp_guid == task_Plain.tp_guid && c.tpi_status == 0).ToList();
                                                                                                                             //bool isPass = checkAllVaild(task_Plain, plain_Items);
                                                                                                                             //if (isPass == false)
                                                                                                                             //{//检测不通过

                    //    return;
                    //}

                    //这里不需要了，上面已经判断，运行中的不再运行了
                    //iot_device_task_plain_item_handle checkHandle = ef.iot_device_task_plain_item_handle.Where(c => c.tpi_tp_guid == tpguid).FirstOrDefault();
                    //if (checkHandle != null)
                    //{
                    //    Console.WriteLine("退出任务，原因任务正在执行," + task_Plain.tp_guid + " " + task_Plain.tp_title);
                    //    return;
                    //}
                    //以下通过检测，可以运行

                    string batch_no = DateTime.Now.ToString("yyyyMMddHHmmss");


                    using (EFYihongIotContext efTran = new EFYihongIotContext())
                    {
                        using (var tran = efTran.Database.BeginTransaction())
                        {
                            try
                            {

                                foreach (iot_device_task_plain_item item in plain_Items)
                                {


                                    //写入处理表
                                    iot_device_task_plain_item_handle processing = new iot_device_task_plain_item_handle();
                                    processing.tpi_id = item.tpi_id;
                                    processing.tpi_guid = item.tpi_guid;
                                    processing.tpi_tp_guid = item.tpi_tp_guid;
                                    processing.tpi_taskobj_guid = item.tpi_taskobj_guid;
                                    processing.tpi_type = item.tpi_type;
                                    processing.tpi_key = item.tpi_key;
                                    processing.tpi_value = item.tpi_value;
                                    processing.tpi_value_rlue = item.tpi_value_rlue;
                                    processing.tpi_order = item.tpi_order;
                                    processing.tpi_repeat_count = item.tpi_repeat_count;
                                    processing.tpi_repeat_interval = item.tpi_repeat_interval;
                                    processing.tpi_status = item.tpi_status;
                                    processing.tpi_title = item.tpi_title;
                                    processing.tpi_execute_batch_no = item.tpi_execute_batch_no;
                                    processing.tpi_execute_delayed_time = item.tpi_execute_delayed_time;
                                    processing.tpi_execute_time = null;
                                    processing.tpi_add_time = DateTime.Now;
                                    efTran.iot_device_task_plain_item_handle.Add(processing);
                                    efTran.SaveChanges();


                                    DateTime? dt = null;
                                    efTran.iot_device_task_plain_item.Where(c => c.tpi_guid == item.tpi_guid).
                     ExecuteUpdate(c => c.SetProperty(p => p.tpi_execute_batch_no, batch_no)
                     .SetProperty(p => p.tpi_complete, 0)
                     .SetProperty(p => p.tpi_execute_delayed_time, dt)
                     .SetProperty(p => p.tpi_execute_time, dt)
                     .SetProperty(p => p.tpi_complete_time, dt)
                     ); /// 更新执行状态               


                                    //string sqlupd2 = "update iot_device_task_plain_item set " +
                                    //     " tpi_execute_batch_no='" + batch_no + "'," +
                                    //  " tpi_complete=0," +
                                    //  " tpi_execute_delayed_time=null," +
                                    //  " tpi_execute_time= null," +
                                    //   " tpi_complete_time=null " +
                                    //  " where tpi_guid='" + item.tpi_guid + "'";
                                    //new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd2);
                                }

                                tran.Commit();
                                tran.Dispose();
                            }
                            catch (Exception ex)
                            {

                                tran.Rollback();
                                tran.Dispose();
                                return;
                            }

                        }
                    }

                    string sqlupd1 = "update iot_device_task_plain set " +
                          " tp_execute_batch_no='" + batch_no + "'," +
                          " tp_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "'," +
                          " tp_complete= 0 " +
                          " where tp_guid='" + task_Plain.tp_guid + "'";
                    int resultcount = new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd1);
                    ef.Dispose();


                    //handlePlainTask(task_Plain.tp_guid);//行完
                }
                else
                {
                    //Thread.Sleep(1000);//留1秒内，预防并发时另一边在写入iot_device_task_plain_item_handle
                    //如果handle表里没有了,更新complete=1
                    iot_device_task_plain_item_handle item = ef.iot_device_task_plain_item_handle.Where(c => c.tpi_tp_guid == tpguid).Take(1).FirstOrDefault();
                    if (item == null)
                    {
                        //已经全部处理完成
                        //更新主单状态
                        string sqlupd = "update iot_device_task_plain set tp_complete=1,tp_set_live_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' where tp_guid='" + tpguid + "'";
                        new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd);

                        new DBIotDeviceTaskPlainLog().addTaskPlianTaskLog(tpguid, 0, "正常");


                        getTaskPlianTask(tpguid);//数据已经处理完成了，重新调用一次更新完成状态
                    }
                }



                //else
                //{
                //第二次到运行时间，上一次还没执行完？重跑一次流程，看是不是没有记录了，没有更新主状态
                //   handlePlainTask(task_Plain.tp_guid);
                // }
                //  UtilRedisNewLife.DelLock("getTaskPlianTask" + tpguid);
                //}
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
            }
        }

        /// <summary>
        /// 根据传感器回传信息时调用，考虑是否调用过于频繁
        /// </summary>
        /// <param name="deviceGuid"></param>
        public void handlePlainTask(string tpguid)
        {
            try
            {

                EFYihongIotContext ef = new EFYihongIotContext();

                iot_device_task_plain_item_handle item = ef.iot_device_task_plain_item_handle.Where(c => c.tpi_tp_guid == tpguid).OrderBy(c => c.tpi_order).Take(1).FirstOrDefault();
                if (item == null)
                {
                    //已经全部处理完成
                    //更新主单状态
                    string sqlupd = "update iot_device_task_plain set tp_complete=1,tp_set_live_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' where tp_guid='" + tpguid + "'";
                    new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd);

                    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLog(tpguid, 0, "正常");
                    return;
                }
                else if (item.tpi_execute_time == null)
                {
                    string sqlupd = "update iot_device_task_plain_item set tpi_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' where tpi_guid='" + item.tpi_guid + "'";
                    new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd);
                }

                Console.WriteLine("流程处理-->" + item.tpi_guid + " " + item.tpi_title);
                //判断处理方式,
                if (item.tpi_type == 0)
                {

                    string commandGuid = "";

                    //0指令
                    iot_device device = new DBIotDeviceCache().getClientDeviceByCache_60Min(item.tpi_taskobj_guid);// new RedisHelper().StringGet<List<iot_device>>("devicelist").Where(c => c.d_guid == item.tpi_taskobj_guid).FirstOrDefault();
                    iot_device_command iot_Device_Command = new DBIotDeviceCommandCache().getCommandByCache(device.d_model_guid, item.tpi_key);
                    iot_device_model device_Model = new DBIotDeviceModelCache().getModelByDeviceCache(item.tpi_taskobj_guid);

                    if (item.tpi_key == "delay")
                    {

                        //延时间
                        //查上一个处理完成时间 加上当前时间
                        if (item.tpi_execute_time == null)
                        {
                            string sqlupd2 = "update iot_device_task_plain_item set " +
                   " tpi_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' " +
                   " where tpi_guid='" + item.tpi_guid + "'";
                            new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd2);

                            item.tpi_execute_delayed_time = DateTime.Now.AddSeconds(double.Parse(item.tpi_value));

                            string sqlupdhandle = "update iot_device_task_plain_item_handle set  " +
                                   " tpi_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "', " +
                " tpi_execute_delayed_time='" + ((DateTime)item.tpi_execute_delayed_time).ToString("yyyy-MM-dd HH:mm:ss") + "' " +
                " where tpi_guid='" + item.tpi_guid + "'";
                            new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupdhandle);



                        }

                        //如果没到时间，继续等待
                        if (item.tpi_execute_delayed_time > DateTime.Now)
                        {
                            return;
                        }
                    }
                    else
                    {
                        //执行指令
                        commandGuid = new ServiceCloudDeviceCommand().sendCommandToGateWay(device.d_guid, item.tpi_key, "流程任务 tpi_id:" + item.tpi_id.ToString());

                    }
                    string sqlupd1 = "update iot_device_task_plain_item set " +
                            " tpi_complete=1," +
                            " tpi_object_guid='" + commandGuid + "'," +
                            " tpi_object_type= 'commandlog'," +
                             " tpi_complete_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' " +
                            " where tpi_guid='" + item.tpi_guid + "'";
                    new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd1);
                    //结束等待
                    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 0, "正常");//日志
                    new DBIotDeviceTaskPlainLog().delHandle(item);//删除待处理记录
                    //handlePlainTask(tpguid);//马上执行下一条 20240319

                }
                else if (item.tpi_type == 1)
                {
                    //1条件,写批号到iot_device_command_Processing，没有记录，表示已经执行完
                    //iot_device_linkage linkage = ef.iot_device_linkage.Where(c => c.l_guid == task_Plain.tp_guid).FirstOrDefault();
                    //new ServiceDeviceLinkageCondition().insertExecuteRecordHandRun(linkage.l_guid);
                    //等待完成，怎么等？，传批次号进去？
                }
                else if (item.tpi_type == 2)
                {
                    //废弃了
                    //2条件是否成立，成立就通过，不成立就停在这里，如温度多少，ec值多少，ph多少，才进行下一步
                    //iot_device_value_current iot_Device_Value_Current = ef.iot_device_value_current.Where(c => c.vc_d_guid == item.tpi_taskobj_guid).FirstOrDefault();
                    //if (iot_Device_Value_Current != null)
                    //{
                    //    if (item.tpi_value_rlue == ">")
                    //    {
                    //        if (!(double.Parse(iot_Device_Value_Current.vc_value) > double.Parse(item.tpi_value)))
                    //        {
                    //            //不成立，运行条件
                    //        }
                    //        else
                    //        {
                    //            //结束等待
                    //            string sqlupd = "update iot_device_task_plain_item set " +
                    //   " tpi_complete=1," +
                    //    " tpi_complete_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' " +
                    //   " where tpi_guid='" + item.tpi_guid + "'";
                    //            new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd);
                    //            new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 0, "正常");
                    //            new DBIotDeviceTaskPlainLog().delHandle(item);
                    //        }
                    //    }
                    //    else if (item.tpi_value_rlue == "<")
                    //    {
                    //        if (!(double.Parse(iot_Device_Value_Current.vc_value) < double.Parse(item.tpi_value)))
                    //        {
                    //            //不成立，运行条件
                    //            //iot_device_linkage linkage = ef.iot_device_linkage.Where(c => c.l_guid == item.tpi_object_guid).FirstOrDefault();
                    //            //if (linkage != null)
                    //            //{
                    //            //    new ServiceDeviceLinkageCondition().insertExecuteRecordHandRun(linkage.l_guid);
                    //            //}
                    //        }
                    //        else
                    //        { //结束等待

                    //            string sqlupd = "update iot_device_task_plain_item set " +
                    //   " tpi_complete=1," +
                    //    " tpi_complete_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' " +
                    //   " where tpi_guid='" + item.tpi_guid + "'";
                    //            new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd);
                    //            new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 0, "正常");
                    //            new DBIotDeviceTaskPlainLog().delHandle(item);
                    //            //handlePlainTask(tpguid);//马上执行下一条
                    //        }
                    //    }
                    //}
                    //else
                    //{
                    //    //处理错误
                    //    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 1, "设备数据 不存在");
                    //    new DBIotDeviceTaskPlainLog().delHandle(item);
                    //    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLog(tpguid, 1, "任务运行失败");
                    //}
                }
                else if (item.tpi_type == 3)
                {  //传感器上传数据
                   //判断上一步tpi_complete=1是否已经处理，论到自己处理没有

                    iot_device device = new DBIotDeviceCache().getClientDeviceByCache_60Min(item.tpi_taskobj_guid);
                    iot_device_command commamditem = new DBIotDeviceCommandCache().getCommandByCache(device.d_model_guid, item.tpi_key);

                    new ServiceCloudDeviceCommand().sendCommandToGateWay(item.tpi_taskobj_guid, commamditem.dc_key, "流程任务 tpi_id:" + item.tpi_id, "", (int)item.tpi_repeat_count, new UtilsDateTime().getIntervalSeccond((double)item.tpi_repeat_interval, "ss"));

                    //更新
                    string sqlupd = "update iot_device_task_plain_item set " +
                  " tpi_complete=1," +
                    " tpi_execute_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "', " +
                   " tpi_complete_time='" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "' " +
                  " where tpi_guid='" + item.tpi_guid + "'";
                    new MySqlYihongIot().Db.Ado.ExecuteCommand(sqlupd);
                    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 0, "正常");
                    new DBIotDeviceTaskPlainLog().delHandle(item);
                    //handlePlainTask(tpguid);//马上执行下一条
                }
              


            }
            catch (Exception ex)
            {

                Console.WriteLine("  LinkageCondition -----error-------" + ex);
                new DBIotSystemLogError().addSystemLogError("流程处理失败，tp_guid:" + tpguid, ex.ToString());

            }

        }

        /// <summary>
        ///检测有效性
        /// </summary>
        /// <param name="plain_Items"></param>
        /// <returns></returns>
        protected bool checkAllVaild(iot_device_task_plain plain, List<iot_device_task_plain_item> plain_Items)
        {
            EFYihongIotContext ef = new EFYihongIotContext();
            bool isPass = true;
            DateTime dtOnline = DateTime.Now.AddMinutes(-2);

            foreach (iot_device_task_plain_item item in plain_Items.Where(c => c.tpi_type == 0 || c.tpi_type == 3).ToList())
            {
                iot_device device = new DBIotDeviceCache().getClientDeviceByCache_60Min(item.tpi_taskobj_guid); //ef.iot_device.Where(c => c.d_guid == item.tpi_taskobj_guid).FirstOrDefault();
                if (device == null)
                {
                    isPass = false;
                    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 1, "设备 不存在");
                    break;
                }


                //判断设备异常问题
                //iot_device_live_state device_State = ef.iot_device_live_state.Where(c => c.ls_d_guid == device.d_guid).FirstOrDefault();
                //if (device_State != null && (device_State.ls_live_state == 2 || device_State.ls_live_state == 3))
                //{
                //    isPass = false;
                //    new ServiceIotTaskPlainLog().addTaskPlianTaskLogItem(item, 1, "设备“" + device.d_name + "”异常");
                //    //return isPass;
                //    break;
                //}


                //判断网关在线
                iot_device_live_state live_State = new DBIotDeviceLiveStateCache().getGateWayIsOnlineByCache(device.d_gw_d_guid);// ef.iot_device_live_state.Where(c => c.ls_d_guid == device.d_gw_d_guid && c.ls_live_state_set_time > dtOnline).FirstOrDefault();
                if (live_State == null)
                {
                    isPass = false;
                    new DBIotDeviceTaskPlainLog().addTaskPlianTaskLogItem(item, 1, "设备“" + device.d_name + "”-网关不在线");
                    break;
                    // return isPass;
                }
            }
            if (isPass == false)
            {
                new DBIotDeviceTaskPlainLog().addTaskPlianTaskLog(plain, 1, "检测异常，任务运行失败");
            }
            ef.Dispose();
            return isPass;
        }


    }
}
